﻿using Core.ProxyService;
using Core.Infrastructure.Settings;
using Microsoft.Practices.Unity;
using Core.Infrastructure.AnimationService;
using Microsoft.Practices.Composite.Events;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using NUnit.Framework;
using CThru.Silverlight;
using TypeMock.ArrangeActAssert;
using Core.ScreenStore.ViewModel;
using Api.Model;
using Core.Infrastructure.EventArgs;
using Core.Infrastructure.ErrorReportService;
using Core.Model;

namespace Core.ScreenStore.Test
{
    [TestFixture]
    class ArticlesViewModelTest
    {
        [Test, SilverlightUnitTest]
        public void OnNavigate_Always_AreArticlesCalled()
        {
            var fakeArticlesModel = GetArticlesModelWithoutArticles();
            ICoreProxyService fakeICoreProxyService = Isolate.Fake.Instance<ICoreProxyService>();
            var articlesViewModel = new ArticlesViewModel(null, null, null, null, fakeICoreProxyService, null, fakeArticlesModel);

            articlesViewModel.OnNavigate();

            Isolate.Verify.WasCalledWithAnyArguments(() => fakeArticlesModel.AreArticlesLoaded);
        }

        [Test, SilverlightUnitTest]
        public void OnNavigate_AreArticlesTrue_CallingGetArticles()
        {
            var fakeArticlesModel = GetArticlesModelWithArticlesButWithoutTags();
            ICoreProxyService fakeICoreProxyService = Isolate.Fake.Instance<ICoreProxyService>();
            var articlesViewModel = new ArticlesViewModel(null, null, null, null, fakeICoreProxyService, null, fakeArticlesModel);

            articlesViewModel.OnNavigate();

            Isolate.Verify.WasCalledWithAnyArguments(() => fakeArticlesModel.GetArticles());
        }

        [Test, SilverlightUnitTest]
        public void OnNavigate_AreArticlesFalse_CallingGetArticlesAsync()
        {
            ICoreProxyService fakeICoreProxyService = Isolate.Fake.Instance<ICoreProxyService>();
            var articlesViewModel = new ArticlesViewModel(null, null, null, null, fakeICoreProxyService, null, GetArticlesModelWithoutArticles());

            articlesViewModel.OnNavigate();

            Isolate.Verify.WasCalledWithAnyArguments(() => fakeICoreProxyService.GetArticlesAsync(null));
        }

        [Test, SilverlightUnitTest]
        public void OnNavigate_AreArticlesFalse_IsBusyTrue()
        {
            ICoreProxyService fakeICoreProxyService = Isolate.Fake.Instance<ICoreProxyService>();
            var articlesViewModel = new ArticlesViewModel(null, null, null, null, fakeICoreProxyService, null, GetArticlesModelWithoutArticles());

            articlesViewModel.OnNavigate();
            Assert.True(articlesViewModel.IsBusy);
        }

        [Test, SilverlightUnitTest]
        public void OnNavigate_ArticlesLoadedCorretcly_IsBusyFalse()
        {
            ICoreProxyService fakeICoreProxyService = GetSuccessfulProxyService();
            var articlesViewModel = new ArticlesViewModel(null, null, null, null, fakeICoreProxyService, null, GetArticlesModelWithoutArticles());

            articlesViewModel.OnNavigate();

            Assert.False(articlesViewModel.IsBusy);
        }

        [Test, SilverlightUnitTest]
        public void OnNavigate_ArticlesLoadedCorretcly_AreTagsAvailableCalled()
        {
            IArticlesModel fakeArticlesModel = Isolate.Fake.Instance<IArticlesModel>();
            ICoreProxyService fakeICoreProxyService = GetSuccessfulProxyService();
            var articlesViewModel = new ArticlesViewModel(null, null, null, null, fakeICoreProxyService, null, fakeArticlesModel);

            articlesViewModel.OnNavigate();

            Isolate.Verify.WasCalledWithAnyArguments(() => fakeArticlesModel.AreTagsAvailable);
        }

        [Test, SilverlightUnitTest]
        public void OnNavigate_ArticlesLoadedCorrectlyTagsAreAvailable_GetTagsCalled()
        {
            IArticlesModel fakeArticlesModel = GetArticlesModelWithTagsButWithoutArticles();
            ICoreProxyService fakeICoreProxyService = GetSuccessfulProxyService();
            IEventAggregator eventAggregator = Isolate.Fake.Instance<IEventAggregator>();
            TagsLoadedEvent tagsLoadedEvent = Isolate.Fake.Instance<TagsLoadedEvent>();
            Isolate.WhenCalled(() => tagsLoadedEvent.Publish(null)).IgnoreCall();
            Isolate.WhenCalled(() => eventAggregator.GetEvent<TagsLoadedEvent>()).DoInstead(context => tagsLoadedEvent);

            var articlesViewModel = new ArticlesViewModel(eventAggregator, null, null, null, fakeICoreProxyService, null, fakeArticlesModel);

            articlesViewModel.OnNavigate();

            Isolate.Verify.WasCalledWithAnyArguments(() => fakeArticlesModel.GetTags());
        }

        [Test, SilverlightUnitTest]
        public void OnNavigate_ArticlesLoadedCorrectlyTagsAreAvailable_EventPublished()
        {
            IArticlesModel fakeArticlesModel = GetArticlesModelWithTagsButWithoutArticles();
            ICoreProxyService fakeICoreProxyService = GetSuccessfulProxyService();
            IEventAggregator eventAggregator = Isolate.Fake.Instance<IEventAggregator>();
            TagsLoadedEvent tagsLoadedEvent = Isolate.Fake.Instance<TagsLoadedEvent>();
            Isolate.WhenCalled(() => tagsLoadedEvent.Publish(null)).IgnoreCall();
            Isolate.WhenCalled(() => eventAggregator.GetEvent<TagsLoadedEvent>()).DoInstead(context => tagsLoadedEvent);

            var articlesViewModel = new ArticlesViewModel(eventAggregator, null, null, null, fakeICoreProxyService, null, fakeArticlesModel);

            articlesViewModel.OnNavigate();

            Isolate.Verify.WasCalledWithAnyArguments(() => tagsLoadedEvent.Publish(null));
        }

        [Test, SilverlightUnitTest]
        public void OnNavigate_ArticlesLoadedCorrectlyTagsAreNotAvailable_GetTagsCalledNotCalled()
        {
            IArticlesModel fakeArticlesModel = GetArticlesModelWithArticlesButWithoutTags();
            ICoreProxyService fakeICoreProxyService = GetSuccessfulProxyService();
            var articlesViewModel = new ArticlesViewModel(null, null, null, null, fakeICoreProxyService, null, fakeArticlesModel);

            articlesViewModel.OnNavigate();

            Isolate.Verify.WasNotCalled(() => fakeArticlesModel.GetTags());
        }

        [Test, SilverlightUnitTest]
        public void OnNavigateTag_Always_GetArticlesCalled()
        {
            IArticlesModel fakeArticlesModel = GetArticlesModelWithArticlesButWithoutTags();
            ICoreProxyService fakeICoreProxyService = GetSuccessfulProxyService();
            var articlesViewModel = new ArticlesViewModel(null, null, null, null, fakeICoreProxyService, null, fakeArticlesModel);

            articlesViewModel.OnNavigate(new Tag() { Name = "Rss" });

            Isolate.Verify.WasCalledWithAnyArguments(() => fakeArticlesModel.GetArticles());
        }

        [Test, SilverlightUnitTest]
        public void OnNavigate_GetArticlesFailed_IsBusyFalse()
        {
            ICoreProxyService fakeICoreProxyService = GetUnsuccessfulProxyService();
            IErrorReportService fakeErrorReportService = Isolate.Fake.Instance<IErrorReportService>();
            var articlesViewModel = new ArticlesViewModel(null, null, null, null, fakeICoreProxyService, fakeErrorReportService, GetArticlesModelWithoutArticles());

            articlesViewModel.OnNavigate();

            Assert.False(articlesViewModel.IsBusy);
        }

        [Test, SilverlightUnitTest]
        public void OnNavigate_GetArticlesFailed_CalledReportError()
        {
            ICoreProxyService fakeICoreProxyService = GetUnsuccessfulProxyService();
            IErrorReportService fakeErrorReportService = Isolate.Fake.Instance<IErrorReportService>();
            var articlesViewModel = new ArticlesViewModel(null, null, null, null, fakeICoreProxyService, fakeErrorReportService, GetArticlesModelWithoutArticles());

            articlesViewModel.OnNavigate();

            Isolate.Verify.WasCalledWithAnyArguments(() => fakeErrorReportService.Report(""));
        }

        [Test, SilverlightUnitTest]
        public void ActivateScreen_EventAggregator_CallingGetEvent()
        {
            IEventAggregator fakeIEventAggregator = Isolate.Fake.Instance<IEventAggregator>();
            ScreenActivateEvent screenActivateEvent = Isolate.Fake.Instance<ScreenActivateEvent>();
            Isolate.WhenCalled(() => fakeIEventAggregator.GetEvent<ScreenActivateEvent>()).DoInstead(context => screenActivateEvent);
            ICoreProxyService fakeICoreProxyService = Isolate.Fake.Instance<ICoreProxyService>();
            var articlesViewModel = new ArticlesViewModel(fakeIEventAggregator, null, null, null, fakeICoreProxyService, null, GetArticlesModelWithoutArticles());      
            
            articlesViewModel.SelectArticle(new Article());

            Isolate.Verify.WasCalledWithAnyArguments(() => fakeIEventAggregator.GetEvent<ScreenActivateEvent>());
        }

        private static ICoreProxyService GetSuccessfulProxyService()
        {
            ICoreProxyService fakeICoreProxyService = Isolate.Fake.Instance<ICoreProxyService>();
            Isolate.WhenCalled(() => fakeICoreProxyService.GetArticlesAsync(null)).DoInstead(context =>
            {
                var lambda = context.Parameters[0] as Action<ArticlesDownloadedEventArgs>;
                var args = new ArticlesDownloadedEventArgs(null, false, null, new List<Article>() { new Article() } );
                lambda(args);
            });

            return fakeICoreProxyService;
        }

        private static ICoreProxyService GetUnsuccessfulProxyService()
        {
            ICoreProxyService fakeICoreProxyService = Isolate.Fake.Instance<ICoreProxyService>();
            Isolate.WhenCalled(() => fakeICoreProxyService.GetArticlesAsync(null)).DoInstead(context =>
            {
                var lambda = context.Parameters[0] as Action<ArticlesDownloadedEventArgs>;
                var args = new ArticlesDownloadedEventArgs(new Exception(), true, null, null);
                lambda(args);
            });

            return fakeICoreProxyService;
        }

        private static IArticlesModel GetArticlesModelWithTagsAndArticles()
        {
            IArticlesModel fakeArticlesModel = Isolate.Fake.Instance<IArticlesModel>();
            Isolate.WhenCalled(() => fakeArticlesModel.AreArticlesLoaded).DoInstead(context => true);
            Isolate.WhenCalled(() => fakeArticlesModel.GetArticles()).DoInstead(context => new List<Article>() { new Article() });
            Isolate.WhenCalled(() => fakeArticlesModel.AreTagsAvailable).DoInstead(context => true);
            Isolate.WhenCalled(() => fakeArticlesModel.GetTags()).DoInstead(context => new List<Tag>() { new Tag() { Name = "Rss" } });

            return fakeArticlesModel;
        }

        private static IArticlesModel GetArticlesModelWithTagsButWithoutArticles()
        {
            IArticlesModel fakeArticlesModel = Isolate.Fake.Instance<IArticlesModel>();
            Isolate.WhenCalled(() => fakeArticlesModel.AreArticlesLoaded).DoInstead(context => false);
            Isolate.WhenCalled(() => fakeArticlesModel.AreTagsAvailable).DoInstead(context => true);
            Isolate.WhenCalled(() => fakeArticlesModel.GetTags()).DoInstead(context => new List<Tag>() { new Tag() { Name = "Rss" } });

            return fakeArticlesModel;
        }

        private static IArticlesModel GetArticlesModelWithArticlesButWithoutTags()
        {
            IArticlesModel fakeArticlesModel = Isolate.Fake.Instance<IArticlesModel>();
            Isolate.WhenCalled(() => fakeArticlesModel.AreArticlesLoaded).DoInstead(context => true);
            Isolate.WhenCalled(() => fakeArticlesModel.GetArticles()).DoInstead(context => new List<Article>() { new Article() });
            Isolate.WhenCalled(() => fakeArticlesModel.AreTagsAvailable).DoInstead(context => false);

            return fakeArticlesModel;
        }

        private static IArticlesModel GetArticlesModelWithoutArticles()
        {
            IArticlesModel fakeArticlesModel = Isolate.Fake.Instance<IArticlesModel>();
            Isolate.WhenCalled(() => fakeArticlesModel.AreArticlesLoaded).DoInstead(context => false);

            return fakeArticlesModel;
        }
    }
}
